#######这一模块改自别人代码。
#######主要计算了通讯录，top5，家人，时间间隔的一些特征。
#######主要通过DataFrame来实现


import os
import pandas as pd
import datetime 
import re
from copy import deepcopy
def get_root_dir(path):
    path_list=path.split(os.path.sep)
    index=path_list.index("featurelib")
    return os.path.sep.join(path_list[:index+1])
    
class CallUnBase0V1Module1():
    def __init__(self):
        cur_path=(os.path.abspath('.'))
        root_path=get_root_dir(cur_path)
        path=os.path.join(root_path,'feature_conf', 'call','un','call_un_base0_v1', 'call_un_base0_v1_module1.featlist')
        self.res_map={k.strip().split('|')[0].strip():'None' for k in open(path,encoding='utf-8')}
            
    def main(self,data):
        self.gen_tags(data)
        res_map=self.gen_fea()
        return res_map
    
    def gen_tags(self,data):
        raw_df = pd.DataFrame(data['call_list'])
        if raw_df.shape[0] > 0:
            raw_df['call_dt']=raw_df['calltime'].map(datetime.datetime.date)
            raw_df['sample_dt'] = data['apply_time'].date()
            raw_df['days_gap'] = (raw_df['sample_dt'] - raw_df['call_dt']).map(lambda x:x.days)
            raw_df['period_flag'] = raw_df['calltime'].map(lambda x: self.caculate_hour(str(x)[11:13]))
            self.normal_sub2 = data['country_info'].get('normal_sub2')
            raw_df['mobile_flag'] = raw_df['phone'].map(
                lambda x: 1 if len(self.normal_sub2)>0 and str(x)[:len(self.normal_sub2[0])] in self.normal_sub2 else 0)

            raw_df['name_flag'] = raw_df['name'].map(lambda x: '1' if x and len(x.strip()) > 0 else '0')
            raw_df['type_flag'] = raw_df['type'].map(lambda x: str(x) if str(x) in ['1', '2'] else 'other')

            self.family_names = data['country_info'].get('family_names')
            raw_df['family_flag'] = raw_df['name'].map(lambda x: '1' if str(x).strip().lower() in self.family_names else '0')
            raw_df['all_flag'] = ''
            raw_df['duration'][raw_df.duration < 0] = 0
            raw_df['duration_flag'] = raw_df['duration'].map(lambda x: '0' if x <= 0 else '1' if x < 60 else '2')
            raw_df = raw_df.sort_values(by=['calltime','phone'], ascending=True)
        self.raw_df=deepcopy(raw_df)


    def gen_fea(self):
        res_map=deepcopy(self.res_map)
        raw_df=deepcopy(self.raw_df)
            #衍生类似contact特征
        if raw_df.shape[0]>0:
            phone_df = raw_df[raw_df['name_flag'] == '1']
            if phone_df.shape[0] > 0:
                phone_df = phone_df[['phone' ,'name', 'mobile_flag', 'sample_dt']]
                phone_df = phone_df.drop_duplicates(subset=['phone'], keep='first').reset_index(drop=True)
                res_map['contact_norm_cnt'] = (phone_df['mobile_flag'] == 1).sum()
                res_map['contact_norm_cnt_rate'] = phone_df['mobile_flag'].mean()
                for prefix in self.normal_sub2:
                    phone_df['mobile_flag_' + prefix] = phone_df['phone'].map(
                        lambda x: 1 if str(x)[:len(prefix)] == prefix else 0)
                    res_map[f'contact_mobile_flag_{prefix}_cnt'] = phone_df['mobile_flag_' + prefix].sum()
                    res_map[f'contact_mobile_flag_{prefix}_rate'] = phone_df['mobile_flag_' + prefix].mean()
                res_map['contact_cnt'] = phone_df.shape[0]

            # 只取近180天的通话记录
            raw_df = raw_df[raw_df['days_gap'] <= 180]
            if raw_df.shape[0] > 0:
                # 开始计算特征
                type_list = ['all_flag', 'type_flag', 'name_flag', 'duration_flag', 'period_flag']
                days_list = {'all': '_all', 90: '_3m', 30: '_1m', 7: "_7d"}
                for window in days_list.keys():
                    suffix_name = days_list[window]
                    if window == 'all':
                        windows_df = raw_df
                    else:
                        windows_df = raw_df[raw_df["days_gap"] <= window]

                    for index in range(len(type_list)):
                        if index == 0:
                            col2_list = type_list
                        else:
                            col2_list = type_list[index + 1:]
                        col1 = type_list[index]
                        col_name1 = col1.split('_')[0]
                        for value1 in windows_df[col1].unique():
                            value1_df = windows_df[windows_df[col1] == value1]
                            if value1_df.shape[0] > 0:
                                for col2 in col2_list:
                                    col_name2 = col2.split('_')[0]
                                    for value2 in value1_df[col2].unique():
                                        value2_df = value1_df[value1_df[col2] == value2]
                                        if value2_df.shape[0] > 0:
                                            col_name = 'call_' + col_name1 + value1 + '_' + col_name2 + value2
                                            if 'typeother' in col_name and 'duration1' in col_name:
                                                continue
                                            if 'typeother' in col_name and 'duration2' in col_name:
                                                continue
                                            # 计算top5特征
                                            top_call5 = list(
                                                value2_df['phone'].value_counts().reset_index().sort_values(['count','phone'],ascending=False)['phone'][:5])
                                            top_call5_df = value2_df[value2_df['phone'].map(lambda x: x in top_call5)]
                                            if 'duration0' not in col_name and 'typeother' not in col_name:
                                                res_map[col_name + '_top5_duration_avg' + suffix_name] = top_call5_df[
                                                    'duration'].mean()
                                                res_map[col_name + '_top5_duration_sum' + suffix_name] = top_call5_df[
                                                    'duration'].sum()
                                            res_map[col_name + '_top5_cnt' + suffix_name] = top_call5_df.shape[0]

                                            if not (col1 == 'all_flag' and col2 == 'all_flag'):
                                                res_map[col_name + '_top5_rate' + suffix_name] = res_map[
                                                                                                    col_name + '_top5_cnt' + suffix_name] / \
                                                                                                value1_df.shape[0]
                                                if 'duration0' not in col_name and 'typeother' not in col_name:
                                                    res_map[col_name + '_top5_duration_rate' + suffix_name] = res_map[
                                                                                                                col_name + '_top5_duration_sum' + suffix_name] / \
                                                                                                            value1_df[
                                                                                                                'duration'].sum()

                                            # 衍生近亲通话记录
                                            if col1 == 'all_flag' and col2 in ['all_flag', 'type_flag', 'duration_flag']:
                                                family_df = value2_df[value2_df['family_flag'] == '1']

                                                res_map[col_name + '_family_cnt' + suffix_name] = family_df.shape[0]
                                                res_map[col_name + '_family_dis_cnt' + suffix_name] = len(
                                                    family_df['phone'].unique())

                                                if 'duration0' not in col_name and 'typeother' not in col_name:
                                                    res_map[col_name + '_family_duration_max' + suffix_name] = family_df[
                                                        'duration'].max()
                                                    res_map[col_name + '_family_duration_avg' + suffix_name] = family_df[
                                                        'duration'].mean()
                                                    res_map[col_name + '_family_duration_sum' + suffix_name] = family_df[
                                                        'duration'].sum()

                                                if not (col1 == 'all_flag' and col2 == 'all_flag'):
                                                    res_map[col_name + '_family_rate' + suffix_name] = res_map[
                                                                                                        col_name + '_family_cnt' + suffix_name] / \
                                                                                                    value1_df.shape[0]
                                                    if 'duration0' not in col_name and 'typeother' not in col_name:
                                                        res_map[col_name + '_family_duration_rate' + suffix_name] = res_map[
                                                                                                                        col_name + '_family_duration_sum' + suffix_name] / \
                                                                                                                    value1_df[
                                                                                                                        'duration'].sum()

                                            res_map[col_name + '_cnt' + suffix_name] = value2_df.shape[0]
                                            res_map[col_name + '_dis_cnt' + suffix_name] = len(value2_df['phone'].unique())
                                            # 静默间隔类特征
                                            if col1 == 'all_flag' and col2 in ['all_flag', 'type_flag', 'name_flag',
                                                                            'duration_flag']:
                                                value2_df['call_dt_shift'] = value2_df['call_dt'].shift(1)
                                                value2_df['call_days_gap'] = (
                                                        value2_df['call_dt'] - value2_df['call_dt_shift']).map(lambda x:x.days if type(x)!=float else None)
                                                res_map[col_name + '_day_gap_max' + suffix_name] = value2_df[
                                                    'call_days_gap'].max()
                                                res_map[col_name + '_day_gap_avg' + suffix_name] = value2_df[
                                                    'call_days_gap'].mean()

                                            if 'duration0' not in col_name and 'typeother' not in col_name:
                                                res_map[col_name + '_duration_max' + suffix_name] = value2_df[
                                                    'duration'].max()
                                                res_map[col_name + '_duration_avg' + suffix_name] = value2_df[
                                                    'duration'].mean()
                                                res_map[col_name + '_duration_sum' + suffix_name] = value2_df[
                                                    'duration'].sum()

                                            if not (col1 == 'all_flag' and col2 == 'all_flag'):
                                                res_map[col_name + '_rate' + suffix_name] = res_map[
                                                                                                col_name + '_cnt' + suffix_name] / \
                                                                                            value1_df.shape[0]
                                                res_map[col_name + 'dis_rate' + suffix_name] = res_map[
                                                                                                col_name + '_dis_cnt' + suffix_name] / len(
                                                    value1_df['phone'].unique())
                                                if 'duration0' not in col_name and 'typeother' not in col_name:
                                                    res_map[col_name + '_duration_rate' + suffix_name] = res_map[
                                                                                                            col_name + '_duration_sum' + suffix_name] / \
                                                                                                        value1_df[
                                                                                                            'duration'].sum()
        return res_map
    

    def caculate_hour(self,hour):
        hour = int(hour)
        if hour >= 6 and hour < 9:
            return '6_9'
        elif hour >= 9 and hour < 12:
            return '9_12'
        elif hour >= 12 and hour < 14:
            return '12_14'
        elif hour >= 14 and hour < 17:
            return '14_17'
        elif hour >= 17 and hour < 20:
            return '17_20'
        elif hour >= 20 and hour < 23:
            return '20_23'
        else:
            return '23_6'

  